﻿using UnityEngine.Pool;

namespace System.Collections.Generic {

    internal sealed class KHBD_SortedCollection<TItem> : KHBD_Object, ICollection<TItem> where TItem : class {

        public static readonly ObjectPool<KHBD_SortedCollection<TItem>> Pool = new(() => new(true),
            actionOnGet: item => item.Initialize(), actionOnRelease: item => item.Dispose(), maxSize: 1024 * 1024, collectionCheck: false);

        private static readonly ObjectPool<LinkedList<TItem>> LinkedListPool = new(() => new(), actionOnRelease: item => item.Clear(), maxSize: 1024 * 1024, collectionCheck: false);

        private Dictionary<TItem, LinkedListNode<TItem>> m_NodeDictionary;
        private LinkedList<TItem> m_ItemList;

        public int Count => m_ItemList.Count;

        bool ICollection<TItem>.IsReadOnly => false;

        public KHBD_SortedCollection() : base() {
            Initialize();
        }

        private KHBD_SortedCollection(bool _) : base() {
        }

        private void Initialize() {
            m_NodeDictionary = DictionaryPool<TItem, LinkedListNode<TItem>>.Get();
            m_ItemList = LinkedListPool.Get();
        }

        protected override void Dispose() {
            DictionaryPool<TItem, LinkedListNode<TItem>>.Release(m_NodeDictionary);
            m_NodeDictionary = null;
            LinkedListPool.Release(m_ItemList);
            m_ItemList = null;
        }

        public void Clear() {
            m_NodeDictionary.Clear();
            m_ItemList.Clear();
        }

        public bool Contains(TItem item) => item != null && m_NodeDictionary.ContainsKey(item);

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
        public IEnumerator<TItem> GetEnumerator() => m_ItemList.GetEnumerator();

        public void Add(TItem item) {
            if (!m_NodeDictionary.ContainsKey(item)) {
                var node = m_ItemList.AddLast(item);
                m_NodeDictionary.Add(item, node);
            }
        }

        public bool Remove(TItem item) {
            if (m_NodeDictionary.ContainsKey(item)) {
                var node = m_NodeDictionary[item];
                m_ItemList.Remove(node);
                m_NodeDictionary.Remove(item);
                return true;
            }
            return false;
        }

        public void CopyTo(TItem[] array, int arrayIndex) {
            UnityEngine.Assertions.Assert.IsNotNull(array);

            var i = 0;
            foreach (var item in this) {
                array[arrayIndex + i++] = item;
            }
        }
    }
}
